home *** CD-ROM | disk | FTP | other *** search
- /*
- ** patch.library
- **
- ** Copyright © 1993-1997 by Stefan Fuchs
- ** Freely distributable.
- */
-
- #ifndef _PATCH_INCLUDES_H
- #include "patch_includes.h"
- #endif
-
- /* Functions used by InstallPatchTags() and RemovePatchTags() */
-
-
- /****i* patch.library/RemoveSystemNodeWithTest ***************************************
- *
- * NAME
- * RemoveSystemNodeWithTest -- Remove all nodes required for patching a
- * function, if possible
- *
- * SYNOPSIS
- * error = RemoveSystemNodeWithTest( master )
- *
- * ULONG RemoveSystemNodeWithTest( struct MasterPatch *);
- *
- * FUNCTION
- * Remove all nodes required for patching a function, if no
- * PS_USER_TYPE or PS_SYSTEM_TYPE exists for the same function.
- *
- * INPUTS
- * master = pointer to a MasterPatch structure
- *
- * RESULT
- * error = errorcode as defined in patch.h
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * RemoveSystemNode(), AddSystemNode(), patch.h
- *
- ******************************************************************************
- *
- */
-
- ULONG RemoveSystemNodeWithTest( struct MasterPatch *master)
- {
- ULONG result = 0L;
- if( FindType( (struct List *)(&(master->MPS_PatchHeader)), PS_TYPE_USER) == NULL)
- {
- if( FindType( (struct List*)(&(master->MPS_PatchHeader)), PS_TYPE_SYSTEM) == NULL)
- {
- result = RemoveSystemNode( master);
- }
- }
- return( result);
- }
-
-
- /****i* patch.library/RemoveSystemNode ***************************************
- *
- * NAME
- * RemoveSystemNode -- Remove all nodes required for patching a
- * function, if possible
- *
- * SYNOPSIS
- * error = RemoveSystemNode( master )
- *
- * ULONG RemoveSystemNode( struct MasterPatch *);
- *
- * FUNCTION
- * Remove all nodes required for patching a function.
- * ( PS_TYPE_MASTER, PS_TYPE_START,PS_TYPE_ORIG,PS_TYPE_END)
- * Step 1: Remove patches from the jump-table via DisconnectStartType()
- * Step 2: Test, if PS_TYPE_START is in use
- * Step 3: Remove PS_TYPE_ORIG
- * Step 4: Remove PS_TYPE_START
- * Step 5: Remove PS_TYPE_END
- * Step 6: CloseLibObject()
- * Step 7: Remove PS_TYPE_MASTER
- *
- * INPUTS
- * master = pointer to a MasterPatch structure
- *
- * RESULT
- * error = errorcode as defined in patch.h
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * AddSystemNode(), patch.h
- *
- ******************************************************************************
- *
- */
-
- ULONG RemoveSystemNode( struct MasterPatch *master)
- {
- ULONG result;
-
- Forbid();
- result = DisconnectStartType( master);
- if( result == PATERR_Ok)
- {
- result = TestUsage( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_START));
- if( result == PATERR_Ok)
- {
- result = RemStruct( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_ORIG));
- if( result == PATERR_Ok)
- {
- Permit();
- /* Nothing should cause an error after this point (handle is no longer valid) */
- RemStruct( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_START));
- RemStruct( (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_END));
- CloseLibObject( master->MPS_PatchedLibraryBase, master->MPS_PatchIORequest, master->MPS_Flags);
- RemStruct( (struct Patch *)master);
- return(PATERR_Ok);
- }
- }
- ConnectStartType( master);
- }
- Permit();
- return(result);
- }
-
- /****i* patch.library/AddStruct ***************************************
- *
- * NAME
- * AddStruct -- Create a patch.library structure and add it to a list.
- *
- * SYNOPSIS
- * structure = AddStruct( header, name, type, pri )
- *
- * APTR AddStruct( struct List *, STRPTR, UBYTE, BYTE);
- *
- * FUNCTION
- * Create a structure of the given type and and it to the given
- * list.
- *
- * INPUTS
- * header = pointer to a List structure
- * name = pointer to a name for the structure (will be copied)
- * (not supported for all types)
- * type = type of structure to allocate ( PS_TYPE_xxx )
- * pri = position, where to insert the node to the list
- *
- * RESULT
- * structure = newly created structure or NULL on failure
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * RemStruct(), patch.h
- *
- ******************************************************************************
- *
- */
-
- APTR AddStruct( struct List *header, STRPTR name, UBYTE type, BYTE pri)
- {
- struct Patch *patch;
- struct MasterPatch *master;
- ULONG array[2];
-
- switch(type)
- {
- case PS_TYPE_ORIG:
- case PS_TYPE_USER:
- case PS_TYPE_SYSTEM:
- patch = (struct Patch *)ACreateMyListNodeNamedPri( header, sizeof( struct Patch), name, pri);
- if(patch)
- {
- patch->PS_Node.ln_Type = type;
- NewList( &(patch->PS_RemoveHookList));
-
- if( PatchBase->PB_PatchSVActive)
- {
- PatchBase->PB_PatchSVRemoveable++;
- patch->PS_Flags |= PSF_PatchSV;
- }
- }
- return( patch);
-
-
- case PS_TYPE_MASTER:
- master = (struct MasterPatch *)ACreateMyListNodeNamed( header, sizeof( struct MasterPatch), name);
- if( master)
- {
- master->MPS_Node.ln_Type = type;
- NewList( (struct List*)&(master->MPS_PatchHeader));
- }
- return( master);
-
-
- case PS_TYPE_START:
- patch = (struct Patch *)ACreateMyListNodePri( header, sizeof( struct Patch), pri);
- if(patch)
- {
- patch->PS_Node.ln_Type = type;
- NewList( &(patch->PS_RemoveHookList));
- }
- return( patch);
-
-
- case PS_TYPE_END:
- patch = (struct Patch *)ACreateMyListNodePri( header, sizeof( struct Patch), pri);
- if(patch)
- {
- patch->PS_Node.ln_Type = type;
- NewList( &(patch->PS_RemoveHookList));
-
- SetPCode( patch, TAG_DONE);
- GetPatchCodeTemplate( patch, array);
- patch->PS_PatchCode = (struct PatchCode *)array[1];
- }
- return( patch);
-
-
- default:
- return( NULL);
- }
- }
-
- /****i* patch.library/CreatePatchCode ***************************************
- *
- * NAME
- * CreatePatchCode -- Create and initialize a patchcode.
- *
- * SYNOPSIS
- * patch = CreatePatchCode( patch )
- *
- * struct Patch *CreatePatchCode( struct Patch *);
- *
- * FUNCTION
- * Create and initialize a patchcode for a given patch structure.
- *
- * INPUTS
- * patch = pointer to a Patch structure or NULL for no action
- *
- * RESULT
- * patch = pointer to a Patch structure or NULL on failure
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * AddStruct(), patch.h
- *
- ******************************************************************************
- *
- */
-
- struct Patch *CreatePatchCode( struct Patch *patch)
- {
- ULONG array[2];
-
- if(patch)
- {
- GetPatchCodeTemplate( patch, array);
- patch->PS_PatchCode = BAllocmem( array[0], MEMF_CLEAR | MEMF_PUBLIC);
- if( patch->PS_PatchCode)
- {
- CopyMem( (APTR) array[1], patch->PS_PatchCode, array[0]);
- InitPatchCode( patch);
- }
- else
- {
- RemStruct( patch);
- patch = NULL;
- }
- return( patch);
- }
- }
- /****i* patch.library/SetPCode ***************************************
- *
- * NAME
- * SetPCode -- Set the PCode template in the given patch structure.
- *
- * SYNOPSIS
- * SetPCode( patch, taglist )
- *
- * SetPCode( struct Patch *, struct TagItem *taglist);
- *
- * FUNCTION
- * Decide, which PCode template should be used for the given
- * patch structure and taglist.
- * The taglist is only used, for patches of PS_TYPE_USER or
- * PS_TYPE_SYSTEM.
- *
- * INPUTS
- * patch = pointer to a Patch structure or NULL for no action
- * taglist = pointer to a taglist as used with InstallPatchTags()
- *
- * RESULT
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * patch.h
- *
- ******************************************************************************
- *
- */
-
- void SetPCode( struct Patch *patch, struct TagItem *taglist )
- {
- ULONG xresult;
- struct TagItem *origtag;
- if(patch)
- {
- switch(patch->PS_Node.ln_Type)
- {
- case PS_TYPE_USER:
- xresult = GetTagData( PATT_UseXResult, 0L, taglist);
- origtag = FindTagItem(PATT_Original, taglist);
- if( patch->PS_Node.ln_Pri == 0)
- {
- if( xresult) patch->PS_PatchCodeType = PCODE_USER1;
- else patch->PS_PatchCodeType = PCODE_USER0;
- }
- else
- {
- if( xresult)
- {
- if( origtag)
- patch->PS_PatchCodeType = PCODE_USER5;
- else patch->PS_PatchCodeType = PCODE_USER3;
- }
- else
- {
- if( origtag)
- patch->PS_PatchCodeType = PCODE_USER4;
- else patch->PS_PatchCodeType = PCODE_USER2;
- }
- }
- break;
-
- case PS_TYPE_SYSTEM:
- patch->PS_Flags |= PSF_OriginalType; /* SystemType is handled like a UserType with PATT_ORIGINAL set */
- /* This is only required for older versions of PatchSetFunc, */
- /* which do not use PATT_Original */
- patch->PS_PatchCodeType = PCODE_SYSTEM;
- break;
-
- case PS_TYPE_ORIG:
- patch->PS_PatchCodeType = PCODE_ORIG;
- break;
-
- case PS_TYPE_START:
- patch->PS_PatchCodeType = PCODE_START;
- break;
-
- case PS_TYPE_END:
- patch->PS_PatchCodeType = PCODE_END;
- break;
- }
- }
- }
-
-
- /****i* patch.library/RemStruct ***************************************
- *
- * NAME
- * RemStruct -- Remove and deallocate a patch.library structure.
- *
- * SYNOPSIS
- * error = RemStruct( structure )
- *
- * ULONG RemStruct( APTR);
- *
- * FUNCTION
- * Remove and deallocate a patch.library structure, if possible.
- *
- * INPUTS
- * structure = pointer to a patch.library structure
- *
- * RESULT
- * error = errorcode as defined in patch.h
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * AddStruct(), patch.h
- *
- ******************************************************************************
- *
- */
- ULONG RemStruct( struct Patch *patch)
- {
- struct TagItem tlist[2];
- ULONG result;
- UBYTE *memptr;
-
- switch(patch->PS_Node.ln_Type)
- {
- case PS_TYPE_USER:
- case PS_TYPE_DELUSER:
- case PS_TYPE_SYSTEM:
- case PS_TYPE_DELSYSTEM:
- case PS_TYPE_ORIG:
- if( patch->PS_PatchCode)
- {
- result = TestUsage( patch);
- if( result) return(result);
- CallRemoveHooks( patch);
- tlist[0].ti_Tag = PATT_DeleteTaskList;
- tlist[0].ti_Data = 1L;
- tlist[1].ti_Tag = TAG_DONE;
- patch->PS_Flags |= PSF_InternalCall;
- SetPatchA( patch, tlist);
- if( patch->PS_ProjectNode.mln_Succ)
- {
- Remove( (struct Node *)&(patch->PS_ProjectNode));
- }
- if( patch->PS_UserPatchCodeSize)
- {
- memptr = patch->PS_Jsr;
- memptr += 2;
- AFreemem( (APTR)(*((ULONG *)memptr)) );
- }
- AFreemem( patch->PS_PatchCode);
- }
- if( patch->PS_Flags & PSF_PatchSV)
- PatchBase->PB_PatchSVRemoveable--;
- break;
-
-
- case PS_TYPE_MASTER:
- if(((struct MasterPatch *)patch)->MPS_PatchHeader.mlh_Head->mln_Succ) /* Delete structure only, if Patchlist is empty */
- return(-1);
- PreAllocatedStacksFree( (struct MasterPatch *)patch);
- break;
-
-
- case PS_TYPE_START:
- if( patch->PS_PatchCode)
- {
- result = TestUsage( patch);
- if( result) return( result);
- AFreemem( patch->PS_PatchCode);
- }
- break;
-
-
- case PS_TYPE_END:
- break;
-
-
- default:
- return(-1);
- }
- ADeleteMyListNode( (struct Node *)patch);
- return(PATERR_Ok);
- }
-
-
- /****i* patch.library/CloseLibObject ***************************************
- *
- * NAME
- * CloseLibObject -- Close a library type object.
- *
- * SYNOPSIS
- * CloseLibObject( library, iorequest, flags )
- *
- * void CloseLibObject( struct Library *, struct IORequest *, WORD);
- *
- * FUNCTION
- * Close a library type object (library, device or resource).
- * Action depends on the given flags.
- *
- * INPUTS
- * library = pointer to a library, device or resource or NULL for no
- * action
- * iorequest = pointer to an iorequest used to open a device
- * (only for devices)
- * flags = flags indicating the type of library to close.
- *
- * RESULT
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * OpenLibObject(), patch.h
- *
- ******************************************************************************
- *
- */
- void CloseLibObject( struct Library *libbase, struct IORequest *iorequest, WORD flags)
- {
- if( libbase)
- {
- if( flags & MPSF_CloseDev)
- {
- if( iorequest)
- {
- CloseDevice( iorequest);
- AFreemem( iorequest);
- }
- }
-
- if( flags & MPSF_CloseLib)
- {
- CloseLibrary( libbase);
- }
-
- if( flags & MPSF_IncLibUsage)
- {
- libbase->lib_OpenCnt--; /* ATOMIC operation */
- }
- }
- }
-
-
- /****i* patch.library/CallRemoveHooks ***************************************
- *
- * NAME
- * CallRemoveHooks -- Call all hooks, when removing a patch.
- *
- * SYNOPSIS
- * CallRemoveHooks( patch )
- *
- * void CallRemoveHooks( struct Patch *);
- *
- * FUNCTION
- * Call all hooks, because the given patch structure, will be removed.
- *
- * INPUTS
- * patch = pointer to a Patch structure
- *
- * RESULT
- *
- * NOTES
- *
- * BUGS
- *
- * SEE ALSO
- * AddRemoveHook(), patch.h
- *
- ******************************************************************************
- *
- */
- void CallRemoveHooks( struct Patch *patch)
- {
- struct Node *pointer;
-
- for (pointer = (struct Node *)patch->PS_RemoveHookList.lh_Head;
- pointer->ln_Succ;
- pointer = (struct Node *)pointer->ln_Succ)
- {
- CallHookA( (struct Hook *)pointer, (APTR)patch, 0L);
- }
- }
-
-
- /****i* patch.library/LinkPatch ***************************************
- *
- * NAME
- * LinkPatch -- Establish new links between patch structures.
- *
- * SYNOPSIS
- * LinkPatch( master )
- *
- * void LinkPatch( struct MasterPatch *);
- *
- * FUNCTION
- * This is one of the core functions of patch.library.
- * It corrects the sequence of patches within a patched function,
- * by changing the jmp instructions and syncronices patch structures
- * with patch codes.
- *
- * INPUTS
- * master = pointer to a MasterPatch structure
- *
- * RESULT
- *
- * NOTES
- * This routine should never fail.
- * This routine should run disabled until a caches can be flushed out.
- *
- * BUGS
- * Should use a sub-function, when a doing the code changes (portability),
- * which could as well only flush the needed cachelines, if they
- * actually changed.
- *
- * SEE ALSO
- * patch.h
- *
- ******************************************************************************
- *
- */
-
- void LinkPatch( struct MasterPatch *master)
- {
- struct Patch *orig;
- struct Patch *patch;
- struct Patch *endt;
- APTR origpatch;
- APTR endpatch;
- APTR nextpatch1;
- APTR nextpatch2;
- BOOL replacedflag = FALSE;
-
- orig = (struct Patch *)FindType( (struct List *)(&(master->MPS_PatchHeader)), PS_TYPE_ORIG);
- origpatch = &(orig->PS_PatchCode->PC_PatchCodeStart);
-
- endt = (struct Patch *)master->MPS_PatchHeader.mlh_TailPred;
- endpatch = &(endt->PS_PatchCode->PC_PatchCodeStart);
- nextpatch1 = endpatch;
- nextpatch2 = endpatch;
-
-
- for( patch = endt;
- patch->PS_Node.ln_Pred;
- patch = (struct Patch *)patch->PS_Node.ln_Pred)
-
- {
- switch( patch->PS_Node.ln_Type)
- {
- case PS_TYPE_ORIG:
- SetJMPInstr( patch->PS_JmpNext, nextpatch1);
-
- if( replacedflag == FALSE)
- nextpatch2 = &(patch->PS_PatchCode->PC_PatchCodeStart);
- break;
-
- case PS_TYPE_SYSTEM:
- case PS_TYPE_USER:
- if( patch->PS_Node.ln_Pri)
- {
- if( patch->PS_Flags & PSF_OriginalType)
- {
- SetJMPInstr( patch->PS_JmpOrig, endpatch);
- }
- else
- {
- SetJMPInstr( patch->PS_JmpOrig, nextpatch2);
- }
- SetJMPInstr( patch->PS_JmpNext, nextpatch2);
- nextpatch1 = &(patch->PS_PatchCode->PC_PatchCodeStart);
- nextpatch2 = nextpatch1;
- }
- else
- {
- SetJMPInstr( patch->PS_JmpOrig, origpatch);
- SetJMPInstr( patch->PS_JmpNext, nextpatch1);
- nextpatch2 = &(patch->PS_PatchCode->PC_PatchCodeStart);
- replacedflag = TRUE;
- }
- break;
-
- case PS_TYPE_START:
- SetJMPInstr( patch->PS_JmpNext, nextpatch2);
- break;
-
- case PS_TYPE_END:
- nextpatch1 = &(patch->PS_PatchCode->PC_PatchCodeStart);
- nextpatch2 = nextpatch1;
- break;
- }
- }
- }
-